package com.hyt.it.ogt.kq.common.bm.utils;

public class IdWorker {

	/**
	 * 起始时间戳 2017-04-01
	 */
	private static final long epoch = 1491004800000L;
	/**
	 * 机器ID所占的位数
	 */
	private static final long workerIdBits = 5L;
	/**
	 * 数据标识ID所占的位数
	 */
	private static final long dataCenterIdBits = 5L;
	/**
	 * 支持的最大机器ID,结果是31
	 */
	private static final long maxWorkerId = ~(-1L << workerIdBits);
	/**
	 * 支持的最大数据标识ID,结果是31
	 */
	private static final long maxDataCenterId = ~(-1 << dataCenterIdBits);
	/**
	 * 毫秒内序列在id中所占的位数
	 */
	private static final long sequenceBits = 12L;
	/**
	 * 机器ID向左移12位
	 */
	private static final long workerIdShift = sequenceBits;
	/**
	 * 数据标识ID向左移17(12+5)位
	 */
	private static final long dataCenterIdShift = sequenceBits + workerIdBits;
	/**
	 * 时间戳向左移22(12+5+5)位
	 */
	private static final long timestampShift = sequenceBits + workerIdBits + dataCenterIdBits;
	/**
	 * 生成序列的掩码，这里为4095 (0b111111111111=0xfff=4095)
	 */
	private static final long sequenceMask = ~(-1L << sequenceBits);
	/**
	 * 数据标识ID（0～31）
	 */
	private static long dataCenterId;
	/**
	 * 机器ID（0～31）
	 */
	private static long workerId;
	/**
	 * 毫秒内序列（0～4095）
	 */
	private static long sequence;
	/**
	 * 上次生成ID的时间戳
	 */
	private static long lastTimestamp = -1L;

	public IdWorker(long dataCenterId, long workerId) {
		if (dataCenterId > maxDataCenterId || dataCenterId < 0) {
			throw new IllegalArgumentException(String.format("dataCenterId can't be greater than %d or less than 0", maxDataCenterId));
		}
		if (workerId > maxWorkerId || workerId < 0) {
			throw new IllegalArgumentException(String.format("worker Id can't be greater than %d or less than 0", maxWorkerId));
		}
		this.dataCenterId = dataCenterId;
		this.workerId = workerId;
	}

	/**
	 * 获得下一个ID (该方法是线程安全的)
	 * 
	 * @return snowflakeId
	 */
	public synchronized static long nextId() {
		long timestamp = timeGen();
		// 如果当前时间小于上一次ID生成的时间戳,说明系统时钟回退过,这个时候应当抛出异常
		if (timestamp < lastTimestamp) {
			throw new RuntimeException(String.format("Clock moved backwards.  Refusing to generate id for %d milliseconds", lastTimestamp - timestamp));
		}
		// 如果是同一时间生成的，则进行毫秒内序列
		if (timestamp == lastTimestamp) {
			sequence = (sequence + 1) & sequenceMask;
			// 毫秒内序列溢出
			if (sequence == 0) {
				// 阻塞到下一个毫秒,获得新的时间戳
				timestamp = nextMillis(lastTimestamp);
			}
		} else {// 时间戳改变，毫秒内序列重置
			sequence = 0L;
		}
		lastTimestamp = timestamp;
		// 移位并通过按位或运算拼到一起组成64位的ID
		return ((timestamp - epoch) << timestampShift) | (dataCenterId << dataCenterIdShift) | (workerId << workerIdShift) | sequence;
	}

	/**
	 * 返回以毫秒为单位的当前时间
	 * 
	 * @return 当前时间(毫秒)
	 */
	protected static long timeGen() {
		return System.currentTimeMillis();
	}

	/**
	 * 阻塞到下一个毫秒，直到获得新的时间戳
	 * 
	 * @param lastTimestamp
	 *            上次生成ID的时间截
	 * @return 当前时间戳
	 */
	protected static long nextMillis(long lastTimestamp) {
		long timestamp = timeGen();
		while (timestamp <= lastTimestamp) {
			timestamp = lastTimestamp;
		}
		return timestamp;
	}
	
	public static void main(String[] args) {
		System.out.println(getnanoId());
		System.out.println((int)((Math.random()*9+1)*1000));
	}
	
	/**
	 * 阻塞到下一个毫秒，直到获得新的时间戳
	 * 
	 * @param lastTimestamp
	 *            上次生成ID的时间截
	 * @return 当前时间戳
	 */
	public static long getnanoId() {
		long nanoTime = System.nanoTime();
		int eandom4 = (int)((Math.random()*9+1)*1000);
		return nanoTime * 1000 + eandom4;
	}
}
